#pragma once

#include <iosfwd>
#include <exception>
#include <string>
#include <sstream>
#include <exception>

namespace  ckr
{
class Context;

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

template <typename T>
class AssertableValue
{
public:

	AssertableValue(	const T&			valueIn,
							const char *	valueNameIn, 
							Context&			callerIn,
							int				lineNumberIn,
							const char*		srcFileNameIn );

	AssertableValue<T>& should_be;

	void operator==(const T& rhs);
	void operator!=(const T& rhs);

	void operator<(const T& rhs);
	void operator<=(const T& rhs);

	void operator>(const T& rhs);
	void operator>=(const T& rhs);

	void should_be_true();
	void should_be_false();

	void should_equal_impl( const T& other, const char* otherName ); 
		// use SHOULD_EQUAL macro instead of calling this directly.

	void should_not_equal_impl( const T& other, const char* otherName ); 
		// use SHOULD_NOT_EQUAL macro instead of calling this directly.

	void should_be_less_than_impl( const T& other, const char* otherName );
		// use SHOULD_BE_LESS_THAN macro instead of calling this directly.
	
	void should_be_greater_than_impl( const T& other, const char* otherName );
		// use SHOULD_BE_GREATER_THAN macro instead of calling this directly.
	
	void should_be_less_than_or_equal_to_impl( const T& other, const char* otherName );
		// use SHOULD_BE_LESS_THAN_OR_EQUAL_TO macro instead of calling this directly.

	void should_be_greater_than_or_equal_to_impl( const T& other, const char* otherName );
		// use SHOULD_BE_GREATER_THAN_OR_EQUAL_TO macro instead of calling this directly.

	void should_be_between_impl( 
							const T&			lowValueIn,
							const char *	lowValueNameIn, 
							const T&			highValueIn,
							const char *	highValueNameIn );
	
	void should_be_close_to_impl( 
							const T&			otherValueIn,
							const char *	otherValueNameIn, 
							const T&			deltaValueIn,
							const char *	deltaValueNameIn );

	void should_not_be_between_impl( 
							const T&			lowValueIn,
							const char *	lowValueNameIn, 
							const T&			highValueIn,
							const char *	highValueNameIn );

	void should_not_be_close_to_impl( 
							const T&			otherValueIn,
							const char *	otherValueNameIn, 
							const T&			deltaValueIn,
							const char *	deltaValueNameIn );

	void should_be_within_impl( 
							const T&			lowValueIn,
							const char *	lowValueNameIn, 
							const T&			highValueIn,
							const char *	highValueNameIn );

	void should_not_be_within_impl( 
							const T&			lowValueIn,
							const char *	lowValueNameIn, 
							const T&			highValueIn,
							const char *	highValueNameIn );

	void should_be_null_impl();
	
	void should_not_be_null_impl();

private:
	const char *	valueName;
	const T			value;

	Context&			caller;
	int				lineNumber;
	const char*		srcFileName;
};

typedef AssertableValue<void*> AssertablePointer;

}; // end namespace

